<?php
// +----------------------------------------------------------------------
// | Bwsaas
// +----------------------------------------------------------------------
// | Copyright (c) 2015~2020 http://www.buwangyun.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Gitee ( https://gitee.com/buwangyun/bwsaas )
// +----------------------------------------------------------------------
// | Author: buwangyun <hnlg666@163.com>
// +----------------------------------------------------------------------
// | Date: 2020-9-28 10:55:00
// +----------------------------------------------------------------------

namespace buwang\util\wechat;

use app\common\model\MemberMiniapp;
use app\common\model\MemberPayment;
use EasyWeChat\Factory;
use Exception;


/**
 * 租户微信支付统一处理
 */
class WechatPay
{
    /**
     * 微信支付统一下单方法
     * $data = [
     *    'profit_sharing'//分账参数
     *    'bw_member_app_id' //租户应用 ID（必填）
     *    'name'       //产品名称（必填）
     *    'order_no'   //单号（必填）
     *    'total_fee'  //金额（分）（必填）
     *    'openid'     //付款用户openid（必填）
     *    'notify_url' //支付成功回调地址（必填）
     *    'note'       //备注（非必填）
     * ]
     * @param array $data //统一下单参数
     * @param boolean $official //是否公众号支付
     * @param string|null $sub_mch_id //服务商商户号（空是正常支付,不为空是微信服务商模式支付）（非必填）
     * @return array|\EasyWeChat\Payment\Application
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function bwUnifiedOrder(array $data, bool $official = false, string $sub_mch_id = NULL)
    {
        try {
             if(!isset($data['bw_member_app_id'])) return ['code' => 0, 'msg' => '缺少租户应用id参数bw_member_app_id'];
                $config = MemberPayment::getPayConfig($data['bw_member_app_id'], 'wechat');//apiname为 wechat alipay
                if (empty($config) || !$config) {
                    return [
                        'code' => 0,
                        'msg' => '请确认微信支付配置是否有问题!'
                    ];
                }
            $order = [
                'trade_type' => empty($data['trade_type']) ? 'JSAPI' : $data['trade_type'],
                'body' => $data['name'],
                'out_trade_no' => (string)$data['order_no'],
                'total_fee' => $data['total_fee'],   //分
                'notify_url' => $data['notify_url']
            ];
            isset($data['attach']) && $order['attach'] = $data['attach'];//附加数据，在查询API和支付通知中原样返回，可作为自定义参数使用
            if ($sub_mch_id || (isset($config['is_tpa']) && $config['is_tpa'])) {//服务商模式
                $this->checkTPA($config);
                //JSAPI模式下openid必传
                $order['trade_type'] == 'JSAPI' && $order['sub_openid'] = $data['openid'];
                //分账参数
                isset($data['profit_sharing']) && $order['profit_sharing'] = $data['profit_sharing'];
            } else {//普通商户直连模式
                //JSAPI模式下openid必传
                $order['trade_type'] == 'JSAPI' && $order['openid'] = $data['openid'];
            }
            $wechat = self::doPay($data['bw_member_app_id'], $official, $sub_mch_id);
            //判断错误返回
            if (is_array($wechat)) {
                return $wechat;
            }
            $result = $wechat->order->unify($order);
            if ($result['return_code'] == 'SUCCESS') {
                if ($result['result_code'] == 'SUCCESS') {
                    if ($order['trade_type'] == 'JSAPI') {
                        //JSAPI模式
                        return ['code' => 200, 'msg' => '成功', 'data' => $wechat->jssdk->sdkConfig($result['prepay_id'])];
                    } else {
                        //NATIVE模式
                        return ['code' => 200, 'msg' => '成功', 'data' => $result];
                    }
                } else {//支付失败
                    return ['code' => 0, 'msg' => $result['err_code_des']];
                }
            } else {//支付失败
                return ['code' => 0, 'msg' => $result['return_msg']];
            }
        } catch (Exception $e) {
            return ['code' => 0, 'msg' => $e->getMessage()];
        }
    }

    /**
     * 检验服务商配置参数
     * @param array $config
     * @return array
     */
    protected function checkTPA(array $config){
        if(!$config['tpa_appid']) return ['code' => 0, 'msg' => '未配置服务商appid！'];
        if(!$config['tpa_mch_id']) return ['code' => 0, 'msg' => '未配置服务商商户号！'];
        if(!$config['mch_id']) return ['code' => 0, 'msg' => '未配置子商户号！'];
        if (empty($config['tpa_appid']) || empty($config['tpa_mch_id'])) {
            return [
                'code' => 0,
                'msg' => '未配置服务商支付appid或商户号tpa_mch_id'
            ];
        }
    }


    /**
     * 微信支付处理【平台微信支付/服务商支付/】
     * @param integer $bw_member_app_id //租户应用ID
     * @param bool $official /是否为公众号支付
     * @param string|null $sub_mch_id //sub_mch_id 子商户号(是否服务商模式)
     * @param array $extendConfig //与微信支付配置参数合并
     * @return array|\EasyWeChat\Payment\Application
     */
    public function doPay(int $bw_member_app_id = 0, bool $official = false, string $sub_mch_id = NULL, array $extendConfig = [])
    {
        try {
            //租户支付逻辑
            if ($bw_member_app_id) {
                $config = MemberPayment::getPayConfig($bw_member_app_id, 'wechat');//apiname为 wechat alipay
                if (empty($config) || !$config) {
                    return [
                        'code' => 0,
                        'msg' => '请确认微信支付配置是否有问题!'
                    ];
                }
                $bw_member_app = MemberMiniapp::field('miniapp_appid,mp_appid')->where(['id' => $bw_member_app_id])->find();
                if (empty($official) || !$official) { //小程序
                    if (empty($bw_member_app->miniapp_appid)) {
                        return [
                            'code' => 0,
                            'msg' => '未绑定小程序appid'
                        ];
                    }
                    $config['app_id'] = $bw_member_app->miniapp_appid;
                } else {//公众号
                    if (empty($bw_member_app->mp_appid) || !$bw_member_app->mp_appid) {
                        return [
                            'code' => 0,
                            'msg' => '未绑定公众号appid'
                        ];
                    }
                    $config['app_id'] = $bw_member_app->mp_appid;
                }
                //传入sub_mch_id商户号作为判断是否使用的是服务商模式 start
                //服务商支付模式
                if ($sub_mch_id || (isset($config['is_tpa']) && $config['is_tpa'])) {
                    $this->checkTPA($config);
                    $config = array_merge($config, $extendConfig);
                    //服务商模式支付
                    $configTPA['app_id'] = $config['tpa_appid'];//服务商的app_id
                    $configTPA['mch_id'] = $config['tpa_mch_id'];//服务商的商户号
                    $configTPA['key'] = $config['key'];//商户的API密钥
                    $configTPA['cert_path'] = $config['cert_path'];
                    $configTPA['key_path'] = $config['key_path'];
                    //TODO 如果传入子商户号就直接使用，否则使用微信支付配置mch_id
                    $sub_mch_id = !$sub_mch_id ? $config['mch_id']:$sub_mch_id;
                    $sub_appid = empty($official) ? $bw_member_app->miniapp_appid : $bw_member_app->mp_appid; //判断发起支付的是小程序还是公众号
                    return Factory::payment($configTPA)->setSubMerchant($sub_mch_id, $sub_appid);
                } else {
                    return Factory::payment((array)$config);
                }
                //传入sub_mchid商户号作为判断是否使用的是服务商模式 end
            } else {
                //平台支付逻辑
                $config = bw_config('wechat_pay');//总平台的微信支付设置
                $param = [
                    // 必要配置
                    'app_id' => $config['wechat_app_id'],
                    'mch_id' => $config['wechat_mch_id'],
                    'key' => $config['wechat_key'],   // API 密钥
                    // 如需使用敏感接口（如退款、发送红包等）需要配置 API 证书路径(登录商户平台下载 API 证书)
                    //'cert_path'          => 'path/to/your/cert.pem', // XXX: 绝对路径！！！！
                    //'key_path'           => 'path/to/your/key',      // XXX: 绝对路径！！！！
                    //'notify_url'         => '默认的订单回调地址',     // 你也可以在下单时单独设置来想覆盖它
                ];
                if(!$config['wechat_mch_id'] || !$config['wechat_app_id'] || !$config['wechat_key']){
                    return [
                        'code' => 0,
                        'msg' => "请先完善平台微信支付配置"
                    ];
                }
                $param = array_merge($param, $extendConfig);
                return Factory::payment($param);
            }
        } catch (Exception $e) {
            return [
                'code' => 0,
                'msg' => $e->getMessage()
            ];
        }
    }
}